#pragma once
#include "util/Singleton.h"
#include "Types.h"


namespace Boon
{

class BOON_API Timer : public Singleton<Timer>
{
	SINGLETON( Timer )

public:

	/*! \brief		Time that has been passed (in seconds) since start
	*/
	inline const uint_32					Time() const;

	/*! \brief		Framecount that have been rendered since start
	*/
	inline const uint_32					FrameCount() const { return m_FrameCount; }

	/*! \brief		Delta Time used in Gamelogic-Update
	*/
	inline const float						DeltaTime() const { return m_DeltaTime; }

	/*! \brief		Smoothed Delta Time used in Gamelogic-Update
	*/
	inline const float						DeltaTimeSmooth() const { return m_DeltaTimeSmoothed; }

	/*! \brief		Fixed Delta Time used for Physics-Update
	*/
	inline const float						DeltaTimeFixed() const { return m_DeltaTimeFixed; }

	/*! \brief		Rendering Delta Time used for Rendering-Update (Animations etc )
	*/
	inline const float						DeltaTimeRendering() const { return m_DeltaTimeRendering; }

	/*! \brief		Returns timescale manipulating delta time (Default 1.0f )
	*/
	inline const float						TimeScale() const { return m_TimeScale; }

	/*! \brief		Setting timescale manipulating delta time (Default 1.0f; >= 0 )
	*/
	inline void								TimeScale( float scale );

	/*! \brief		Returns the current System-Time
		\return		const uint_32 - System time in milliseconds
	*/
	static const uint_32					TimeStamp();

	inline uint_32							FPSLogic() const { return (uint_32)m_FpsLogic; }
	inline uint_32							FPSRendering() const { return (uint_32)m_FpsRendering; }

private:
	
	/*! \brief		Calculated DeltaTime SmoothDeltaTime
					Note: Should be called before GameLogic Update
	*/
	void									CalculateDeltaTime();

	/*! \brief		Returns true if time limit has exceeded to render a new frame
					Note: Timer will be reset with event Event_OnRender
		\return		True if allowed to advance render simulation
	*/
	bool									CalculateDeltaTimeRendering();

	/*! \brief		Returns true if time limit has exceeded to render a new physics frame
					Note: Timer will be reset with event Event_OnPhysicsUpdate
		\return		Number of (sub)steps that have to be processed, 0 on disallow advance physics simulation
	*/
	uint_32									CalculateDeltaTimeFixed();

	virtual void OnInitialize();

	virtual void OnDestroy();

	// this event callbacks will reset m_TimerRendering & m_TimerFixedUpdate to .0f
	void									OnFrameRendered( const IMessengerEventStrong& edata );
	void									OnPhysicUpdate( const IMessengerEventStrong& edata );
	void									OnConfigiurationUpdate( const IMessengerEventStrong& edata );
	void									OnTimescaleChange( const IMessengerEventStrong& edata );



	uint_32					m_TimeStartup; 				/*!< Timestamp of starting the game */
	uint_32					m_FrameCount; 				/*!< Framecount that have been rendered since start */
	float					m_DeltaTime;				/*!< Delta Time used in Gamelogic-Update */
	float					m_DeltaTimeSmoothed;		/*!< Smoothed Delta Time used in Gamelogic-Update */
	float					m_DeltaTimeFixed;			/*!< Fixed Delta Time used for Physics-Update */
	float					m_DeltaTimeRendering;		/*!< Rendering Delta Time used for Rendering-Update */
	float					m_TimeScale;				/*!< Used to manipulate Delta-Time */
	float					m_TimerRendering;			/*!< Timer that will be used to run rendering at constant frames */
	float					m_TimerFixedUpdate;			/*!<  Timer that will be used to run physics at constant frames */
	float					m_FpsLogic, m_FpsRendering;
	float					m_SmootingDT, m_SmoothingDTRendering;		/*!< Smoothingfactors for fsp calculations */
	uint_32					m_PhysicsMaxSubsteps;

	friend class ProcessManager;
};


}
